#include "BvhFile.h"


BvhFile::BvhFile()
	: QObject()
{

}

BvhFile::~BvhFile()
{

}

void BvhFile::ReadBVH(QString filePath)
{
	QFile file(filePath);
	if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		QTextStream buffer(&file);

		while (!file.atEnd()) {
			QString line = buffer.readLine();
			if (line.contains("HIERARCHY")) {
				ReadHierarchy(buffer);
			} else if (line.contains("MOTION")) {
				ReadMotion(buffer);
			}
		}


		file.close();
	}
}

void BvhFile::WriteBVH(QString filePath)
{
	QFile file(filePath);
	if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
		QTextStream buffer(&file);

		WriteHierarchy(buffer);
		WriteMotion(buffer);

		file.close();
	}
}

BvhJoint* BvhFile::getJointFromName(QString jointName)
{
	QList<BvhJoint*> jointList = m_rootJoint->getJointList();
	for (int n=0;n<jointList.count();n++) {
		if (jointList[n]->getName() == jointName) return jointList[n];
	}
	return 0;
}

double BvhFile::getDataValue(int row, int col)
{
	if (row >= getDataCount()) return 0;
	QList<double> list = m_data[row];
	return list.value(col,-5);
	//return m_data[row].value(col,-m_data[row].count());
}

void BvhFile::setData(int index)
{
	m_rootJoint->setFromData(m_data[index]);
}

void BvhFile::ReadHierarchy(QTextStream& buffer)
{
	QString line = buffer.readLine();
	line.replace("\t"," ");
	QStringList parselist = line.split(" ",QString::SkipEmptyParts);
	if (parselist.value(0) == "ROOT") {
		m_rootJoint = ReadJoint(parselist.value(1),buffer);
		m_rootJoint->setParent(0);
	}
}

BvhJoint* BvhFile::ReadJoint(QString name, QTextStream& buffer)
{
	bool isOpen = false;
	BvhJoint* newJoint = new BvhJoint();
	newJoint->setName(name);
	QString text = buffer.readLine();
	if (text.contains("{")) isOpen = true;
	while (isOpen)
	{
		QString text = buffer.readLine();
		text.replace("\t"," ");
		QStringList parselist = text.split(" ",QString::SkipEmptyParts);
		if (parselist.value(0) == "OFFSET") {
			Vector3f offset;
			offset << parselist.value(1).toDouble() , parselist.value(2).toDouble() , parselist.value(3).toDouble();
			newJoint->setOffset(offset);
		} else if (parselist.value(0) == "CHANNELS") {
			for (int n=0;n<parselist.value(1).toInt();n++) {
				newJoint->addChannel(parselist.value(n+2));
			}
		} else if (parselist.value(0) == "JOINT") {
			BvhJoint* newChildJoint = ReadJoint(parselist.value(1),buffer);
			newChildJoint->setParent(newJoint);
			newJoint->addChild(newChildJoint);
		} else if (parselist.value(0) == "End") {
			BvhJoint* newChildJoint = ReadJoint("End Site",buffer);
			newChildJoint->setParent(newJoint);
			newJoint->addChild(newChildJoint);
		} else if (parselist.value(0) == "}") {
			isOpen = false;
		}
	}
	//qDebug() << "BvhFile::ReadJoint()" << newJoint->getName();
	return newJoint;
}

void BvhFile::WriteHierarchy(QTextStream& buffer)
{
	buffer << "HIERARCHY\n";
	buffer << "ROOT " << m_rootJoint->getName() << "\n";
	m_tabCount = 0;
	buffer.setRealNumberPrecision(4);
	WriteJoint(buffer, m_rootJoint);
}

void BvhFile::WriteJoint(QTextStream& buffer, BvhJoint* jointPtr)
{
	QString tab;
	for (int n=0;n<m_tabCount;n++) tab.append("\t");
	buffer << tab << "{\n";
	tab.append("\t");
	m_tabCount++;
	Vector3f pos = jointPtr->getOffset();
	buffer << tab << "OFFSET" << "\t" << pos.x() << "\t" << pos.y() << "\t" << pos.z() << "\n";
	if (jointPtr->getChannelCount() > 0) {
		buffer << tab << "CHANNELS";
		for (int n=0;n<jointPtr->getChannelCount();n++) buffer << " " << jointPtr->getChannel(n);
		buffer << "\n";
	}
	for (int n=0;n<jointPtr->getChildCount();n++) {
		buffer << tab;
		if (!jointPtr->getChild(n)->getName().contains("End")) buffer << "JOINT ";
		buffer << jointPtr->getChild(n)->getName() << "\n";
		WriteJoint(buffer,jointPtr->getChild(n));
	}
	m_tabCount--;
	tab.chop(1);
	buffer << tab << "}\n";
}

void BvhFile::ReadMotion(QTextStream& buffer)
{
	QString line = buffer.readLine();
	line.replace("\t"," ");
	QStringList parselist = line.split(" ",QString::SkipEmptyParts);
	if (parselist.value(0) == "Frames:") m_frameCount = parselist.value(1).toInt();
	line = buffer.readLine();
	line.replace("\t"," ");
	parselist = line.split(" ",QString::SkipEmptyParts);
	QString text = parselist.value(0) + parselist.value(1);
	if (text == "FrameTime:") m_frameTime = parselist.value(2).toDouble();
	if (m_frameCount != 0) qDebug() << "Frames: " << m_frameCount;
	if (m_frameTime != 0) qDebug() << "Frame Time: " << m_frameTime;
	
	m_data.reserve(m_frameCount);

	//for (int n=0;n<500;n++) {
	for (int n=0;n<m_frameCount;n++) {
		if (buffer.atEnd()) return;
		line = buffer.readLine();
		parselist = line.split("\t",QString::SkipEmptyParts);
		QList<double> valueList;
		for (int d=0;d<parselist.count();d++) {
			valueList.append(parselist[d].toDouble());
		}
		m_data.append(valueList);
	}
	qDebug() << "Loaded" << m_data.count() << "frames";
}

void BvhFile::WriteMotion(QTextStream& buffer)
{
	buffer << "MOTION\n";
	buffer << "Frames:\t" << getDataCount() << "\n";
	buffer.setRealNumberPrecision(10);
	buffer << "Frame Time: " << getFrameTimeInSeconds() << "\n";
	buffer.setRealNumberPrecision(4);
	for (int n=0;n<m_data.count();n++) {
		for (int d=0;d<m_data[n].count();d++) {
			buffer << "\t" << m_data[n].value(d);
		}
		buffer << "\n";
	}
}